package io.itit.ecp.admin.provide.action.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.utils.EcpAdminUtils;
import io.itit.ecp.admin.provide.action.req.CarbonEmissionFactorReq;
import io.itit.ecp.admin.provide.action.req.EmissionReductionFactorQueryReq;
import io.itit.ecp.admin.provide.action.req.EmissionReductionFactorReq;
import io.itit.ecp.admin.provide.action.resp.EmissionReductionFactorResp;
import io.itit.ecp.admin.provide.helper.EmissionReductionFactorHelper;
import io.itit.ecp.admin.provide.renderer.EmissionReductionFactorRenderer;
import io.itit.ecp.admin.server.entity.EmissionReductionFactorEntity;
import io.itit.ecp.admin.server.entity.EnergyConsumptionTypeEntity;
import io.itit.ecp.admin.server.service.IEmissionReductionFactorService;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：碳减因子控制类
 * @Date：Create by 2023-11-23 16:28:52
 */
@Api(tags = "碳减因子")
@RestController
@RequestMapping("/ecp-admin/emissionReductionFactor")
public class EmissionReductionFactorController {

    @Resource
    private IEmissionReductionFactorService emissionReductionFactorService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:search")
    public ResultResp<IPage<EmissionReductionFactorResp>> queryPage(@RequestBody @Validated(IQueryPage.class) EmissionReductionFactorQueryReq req) {
        SpringUtil.getBean(Jackson2ObjectMapperBuilder.class);
        return ResultResp.success(buildQW(req).joinPage(PageUtils.getPage(req, EmissionReductionFactorResp.class), EmissionReductionFactorResp.class));
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:search")
    public ResultResp<EmissionReductionFactorResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        return ResultResp.success(ConvertUtils.copy(emissionReductionFactorService.getById(req.getId()), EmissionReductionFactorResp.class));
    }

    /**
     * 组装查询条件
     *
     * @param req
     * @return
     */
    private static JoinLambdaWrapper<EmissionReductionFactorEntity> buildQW(EmissionReductionFactorQueryReq req) {
        LocalDateTime dateStart = null;
        LocalDateTime dateEnd = null;
        if (StringUtils.isNotEmpty(req.getSolidifyDate())) {
            YearMonth yearMonth = YearMonth.parse(req.getSolidifyDate(), DateTimeFormatter.ofPattern("yyyy-MM"));
            dateStart = yearMonth.atDay(1).atTime(LocalTime.MIN);
            dateEnd = LocalDate.of(yearMonth.getYear(), yearMonth.getMonth(), yearMonth.lengthOfMonth()).atTime(LocalTime.MAX);
        }
        return Joins.of(EmissionReductionFactorEntity.class)
                .selectAll()
                .leftJoin(EnergyConsumptionTypeEntity.class, EnergyConsumptionTypeEntity::getId, EmissionReductionFactorEntity::getEnergyTypeId)
                .selectAs(EnergyConsumptionTypeEntity::getEnergyName, EmissionReductionFactorResp::getEnergyTypeName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getEnergyTypeId()), EmissionReductionFactorEntity::getEnergyTypeId, req.getEnergyTypeId())
                .eq(req.getFactor() != null, EmissionReductionFactorEntity::getFactor, req.getFactor())
                .eq(StringUtils.isNotEmpty(req.getRemark()), EmissionReductionFactorEntity::getRemark, req.getRemark())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), EmissionReductionFactorEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), EmissionReductionFactorEntity::getId, req.getIds())
                .ge(Objects.nonNull(dateStart), EmissionReductionFactorEntity::getSolidifyDate, dateStart)
                .lt(Objects.nonNull(dateEnd), EmissionReductionFactorEntity::getSolidifyDate, dateEnd)
                .orderByDesc(EmissionReductionFactorEntity::getSolidifyDate)
                .orderByDesc(EmissionReductionFactorEntity::getCreateTm);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) EmissionReductionFactorReq req) {
        EmissionReductionFactorEntity emissionReductionFactor = ConvertUtils.convertIgnoreId(req, EmissionReductionFactorEntity.class);
        Date start = DateUtil.beginOfMonth(req.getSolidifyDate());
        Date end = DateUtil.endOfMonth(req.getSolidifyDate());
        long count = emissionReductionFactorService.lambdaQuery()
                .eq(EmissionReductionFactorEntity::getEnergyTypeId, req.getEnergyTypeId())
                .ge(EmissionReductionFactorEntity::getSolidifyDate, start)
                .le(EmissionReductionFactorEntity::getSolidifyDate, end)
                .count();
        GrassException.throwEx(count > 0, "该时段已存在碳减因子，不能重复新增!");
        return ResultResp.success(emissionReductionFactorService.save(emissionReductionFactor));
    }

    @ApiOperation("批量新增")
    @PostMapping("batchAdd")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:add")
    public ResultResp<Boolean> batchAdd(@RequestBody @Validated({IBatch.class}) CarbonEmissionFactorReq req) {
        Long count = emissionReductionFactorService.lambdaQuery()
                .eq(EmissionReductionFactorEntity::getEnergyTypeId, req.getEnergyTypeId())
                .ge(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateStart())
                .le(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateEnd())
                .count();
        GrassException.throwEx(count > 0, "该时段已存在碳减因子，不能重复新增!");

        int compare = req.getSolidifyDateStart().compareTo(req.getSolidifyDateEnd());
        GrassException.throwEx(compare > 0, "结束时间不能大于开始时间！");

        // 组装批量新增数据
        List<EmissionReductionFactorEntity> entityList = IntStream.range(0, EcpAdminUtils.between(req.getSolidifyDateStart(), req.getSolidifyDateEnd(), ChronoUnit.MONTHS).intValue() + 1)
                .mapToObj(t -> {
                    Date newDate = DateUtils.addMonths(req.getSolidifyDateStart(), t);
                    EmissionReductionFactorEntity entity = new EmissionReductionFactorEntity();
                    entity.setSolidifyDate(newDate);
                    entity.setEnergyTypeId(req.getEnergyTypeId());
                    entity.setFactor(req.getFactor());
                    entity.setUnit(req.getUnit());
                    entity.setRemark(req.getRemark());
                    return entity;
                })
                .collect(Collectors.toList());

//        CarbonEmissionFactorHelper.i().setCache(req.getEnergyTypeId(), req.getSolidifyDate(), req.getFactor());

        return ResultResp.success(emissionReductionFactorService.saveBatch(entityList, 1000));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) EmissionReductionFactorReq req) {
        boolean bool = emissionReductionFactorService.updateEmissionReductionFactor(ConvertUtils.copy(req, EmissionReductionFactorEntity.class));
        EmissionReductionFactorHelper.i().setCache(req.getEnergyTypeId(), req.getSolidifyDate(), req.getFactor());
        return ResultResp.success(bool);
    }

    @ApiOperation("批量编辑")
    @PostMapping("batchUpdate")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:update")
    public ResultResp<Boolean> batchUpdate(@RequestBody @Validated({IBatch.class}) EmissionReductionFactorReq req) {
        Long count = emissionReductionFactorService.lambdaQuery()
                .eq(EmissionReductionFactorEntity::getEnergyTypeId, req.getEnergyTypeId())
                .ge(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateStart())
                .le(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateEnd())
                .count();
        GrassException.throwEx(count == 0, "该时段无碳减因子数据，无需更新（如有需要可批量新增）!");

        return ResultResp.success(emissionReductionFactorService.lambdaUpdate()
                .set(EmissionReductionFactorEntity::getFactor, req.getFactor())
                .set(EmissionReductionFactorEntity::getUnit, req.getUnit())
                .set(EmissionReductionFactorEntity::getRemark, req.getRemark())
                .eq(EmissionReductionFactorEntity::getEnergyTypeId, req.getEnergyTypeId())
                .ge(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateStart())
                .le(EmissionReductionFactorEntity::getSolidifyDate, req.getSolidifyDateEnd())
                .update());
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(emissionReductionFactorService.removeById(req.getId()));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(emissionReductionFactorService.removeBatchByIds(req.getIds(), 1000));
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:upload")
    public ResultResp<Integer> upload(@RequestParam("file") MultipartFile file, Boolean ignoreError) {
        return ResultResp.success(ExcelParseManage.i().process(EmissionReductionFactorRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:emissionReductionFactor:export")
    public void export(@RequestBody @Validated(IExport.class) EmissionReductionFactorQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("EmissionReductionFactorExport", JsonUtil.toJson(buildQW(req).joinList(EmissionReductionFactorResp.class)), response);
    }
}
